﻿using LibUsbDotNet;
using LibUsbDotNet.Info;
using LibUsbDotNet.Main;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using XboxOneDriver;
using LibUsbDotNet.WinUsb;
using vJoyInterfaceWrap;
using System.Collections;

namespace XboxOneDriverApp
{
    public partial class GamePadTestForm : Form
    {
        private XboxOneGamepad gamepad;
        private vJoy joystick;
        private vJoy.JoystickState iReport;

        private uint id;

        public GamePadTestForm()
        {
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            gamepad = new XboxOneGamepad();
            gamepad.OnDataArrive += gamepad_OnDataArrive;

            joystick = new vJoy();
            if (!joystick.vJoyEnabled())
            {
                MessageBox.Show("VJoy not enabled!");
                this.Close();
            }

            id = 1;
            VjdStat status = joystick.GetVJDStatus(id);

            if (status != VjdStat.VJD_STAT_FREE && status != VjdStat.VJD_STAT_OWN)
            {
                this.Close();
            }

            // Acquire the target
            if ((status == VjdStat.VJD_STAT_OWN) || ((status == VjdStat.VJD_STAT_FREE) && (!joystick.AcquireVJD(id))))
            {
                MessageBox.Show("Failed to acquire vJoy device number 1");
                this.Close();
            }

            joystick.ResetVJD(id);
        }

        void gamepad_OnDataArrive(XboxOneGamepad pad, XboxOneButtonData buttons)
        {
            iReport.bDevice = (byte)id;

            short max = short.MaxValue;
            ushort umax = ushort.MaxValue;
            short middle = short.MaxValue / 2;

            /*joystick.SetBtn(buttons.a, id, 1);
            joystick.SetBtn(buttons.b, id, 2);
            joystick.SetBtn(buttons.x, id, 3);
            joystick.SetBtn(buttons.y, id, 4);

            joystick.SetBtn(buttons.bumper_left, id, 5);
            joystick.SetBtn(buttons.bumper_right, id, 6);
            joystick.SetBtn(buttons.back, id, 7);
            joystick.SetBtn(buttons.start, id, 8);

            joystick.SetBtn(buttons.stick_left_click, id, 9);
            joystick.SetBtn(buttons.stick_right_click, id, 10);

            joystick.SetBtn(buttons.dpad_up, id, 11);
            joystick.SetBtn(buttons.dpad_down, id, 12);
            joystick.SetBtn(buttons.dpad_left, id, 13);
            joystick.SetBtn(buttons.dpad_right, id, 14);
            joystick.SetBtn(buttons.centerButton, id, 15);

            joystick.SetAxis(buttons.stick_left_x + (short.MaxValue / 2), id, HID_USAGES.HID_USAGE_X);
            joystick.SetAxis(-buttons.stick_left_y + (short.MaxValue / 2), id, HID_USAGES.HID_USAGE_Y);

            joystick.SetAxis(buttons.stick_right_x + (short.MaxValue / 2), id, HID_USAGES.HID_USAGE_RX);
            joystick.SetAxis(-buttons.stick_right_y + (short.MaxValue / 2), id, HID_USAGES.HID_USAGE_RY);

            // get triggers
            /*float leftTrigger = buttons.trigger_left / 2048.0f; // max = 1024
            float rightTrigger = -buttons.trigger_right / 2048.0f; // max = 1024
            short max = short.MaxValue;

            joystick.SetAxis((int)(middle + (rightTrigger * max) + (leftTrigger * max)), id, HID_USAGES.HID_USAGE_Z);

            float leftTrigger = buttons.trigger_left / 1024.0f; // max = 1024
            float rightTrigger = buttons.trigger_right / 1024.0f; // max = 1024
            short max = short.MaxValue;
            joystick.SetAxis((int)(leftTrigger * max), id, HID_USAGES.HID_USAGE_Z);
            joystick.SetAxis((int)(rightTrigger * max), id, HID_USAGES.HID_USAGE_Z);*/

            iReport.AxisX = buttons.stick_left_x + middle;
            iReport.AxisY = -buttons.stick_left_y + middle;
            iReport.AxisXRot = buttons.stick_right_x + middle;
            iReport.AxisYRot = -buttons.stick_right_y + middle;

            float leftTrigger = buttons.trigger_left / 2048.0f; // max = 1024
            float rightTrigger = buttons.trigger_right / 2048.0f; // max = 1024
            iReport.AxisZ = (int)(leftTrigger * umax);
            iReport.AxisZRot = (int)(rightTrigger * umax);

            // Some bitwise magic:
            BitArray bit = new BitArray(new bool[]
                {
                    buttons.a,
                    buttons.b,
                    buttons.x,
                    buttons.y,
                    buttons.bumper_left,
                    buttons.bumper_right,
                    buttons.back,
                    buttons.start,
                    buttons.stick_left_click,
                    buttons.stick_right_click,
                    buttons.centerButton
                });
            int[] result = new int[1];
            bit.CopyTo(result, 0);
            iReport.Buttons = (uint)result[0];


            byte b1 = 1;
            byte b2 = 0;
            byte b3 = 3;
            byte b4 = 2;

            iReport.bHats = (uint)(b4 << 12) | (uint)(b3 << 8) | (uint)(b2 << 4) | (uint)b1; // up

            joystick.UpdateVJD(id, ref iReport);


            btn_A.Invoke((Action)(() =>
            {
                btn_BigButton.Visible = buttons.centerButton;

                btn_Start.Visible = buttons.start;
                btn_Back.Visible = buttons.back;

                btn_A.Visible = buttons.a;
                btn_B.Visible = buttons.b;
                btn_X.Visible = buttons.x;
                btn_Y.Visible = buttons.y;

                btn_DpadUp.Visible = buttons.dpad_up;
                btn_DpadDown.Visible = buttons.dpad_down;
                btn_DpadLeft.Visible = buttons.dpad_left;
                btn_DpadRight.Visible = buttons.dpad_right;

                btn_LeftBumper.Visible = buttons.bumper_left;
                btn_rightBumper.Visible = buttons.bumper_right;
                btn_LeftStick.Visible = buttons.stick_left_click;
                btn_RightStick.Visible = buttons.stick_right_click;

                btn_LeftTrigger.Value = buttons.trigger_left;
                btn_RightTrigger.Value = buttons.trigger_right;

                btn_LeftStickX.Value = buttons.stick_left_x;
                btn_LeftStickY.Value = buttons.stick_left_y;
                btn_RightStickX.Value = buttons.stick_right_x;
                btn_RightStickY.Value = buttons.stick_right_y;
            }));
        }
        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            gamepad.Dispose();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            joystick.SetBtn(gamepad.Data.a, id, 1); // keep updating so we dont lose track

            // check if we are connected
            if (!gamepad.Connected)
            {
                gamepad.Connect();
            }
        }

      


    }
}
